home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / lib / python2.4 / tarfile.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2007-04-29  |  52.9 KB  |  1,964 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. '''Read from and write to tar format archives.
  5. '''
  6. __version__ = '$Revision: 41341 $'
  7. version = '0.6.4'
  8. __author__ = 'Lars Gust\xe4bel (lars@gustaebel.de)'
  9. __date__ = '$Date: 2005-10-28 16:00:51 +1000 (Fri, 28 Oct 2005) $'
  10. __cvsid__ = '$Id: tarfile.py 41341 2005-10-28 06:00:51Z neal.norwitz $'
  11. __credits__ = 'Gustavo Niemeyer, Niels Gust\xe4bel, Richard Townsend.'
  12. import sys
  13. import os
  14. import shutil
  15. import stat
  16. import errno
  17. import time
  18. import struct
  19. if sys.platform == 'mac':
  20.     raise ImportError, 'tarfile does not work for platform==mac'
  21.  
  22.  
  23. try:
  24.     import grp
  25.     import pwd
  26. except ImportError:
  27.     grp = pwd = None
  28.  
  29. __all__ = [
  30.     'TarFile',
  31.     'TarInfo',
  32.     'is_tarfile',
  33.     'TarError']
  34. NUL = '\x00'
  35. BLOCKSIZE = 512
  36. RECORDSIZE = BLOCKSIZE * 20
  37. MAGIC = 'ustar'
  38. VERSION = '00'
  39. LENGTH_NAME = 100
  40. LENGTH_LINK = 100
  41. LENGTH_PREFIX = 155
  42. MAXSIZE_MEMBER = 0x1FFFFFFFFL
  43. REGTYPE = '0'
  44. AREGTYPE = '\x00'
  45. LNKTYPE = '1'
  46. SYMTYPE = '2'
  47. CHRTYPE = '3'
  48. BLKTYPE = '4'
  49. DIRTYPE = '5'
  50. FIFOTYPE = '6'
  51. CONTTYPE = '7'
  52. GNUTYPE_LONGNAME = 'L'
  53. GNUTYPE_LONGLINK = 'K'
  54. GNUTYPE_SPARSE = 'S'
  55. SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, CONTTYPE, CHRTYPE, BLKTYPE, GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, GNUTYPE_SPARSE)
  56. REGULAR_TYPES = (REGTYPE, AREGTYPE, CONTTYPE, GNUTYPE_SPARSE)
  57. S_IFLNK = 40960
  58. S_IFREG = 32768
  59. S_IFBLK = 24576
  60. S_IFDIR = 16384
  61. S_IFCHR = 8192
  62. S_IFIFO = 4096
  63. TSUID = 2048
  64. TSGID = 1024
  65. TSVTX = 512
  66. TUREAD = 256
  67. TUWRITE = 128
  68. TUEXEC = 64
  69. TGREAD = 32
  70. TGWRITE = 16
  71. TGEXEC = 8
  72. TOREAD = 4
  73. TOWRITE = 2
  74. TOEXEC = 1
  75.  
  76. def nts(s):
  77.     '''Convert a null-terminated string buffer to a python string.
  78.     '''
  79.     return s.rstrip(NUL)
  80.  
  81.  
  82. def calc_chksum(buf):
  83.     """Calculate the checksum for a member's header. It's a simple addition
  84.        of all bytes, treating the chksum field as if filled with spaces.
  85.        buf is a 512 byte long string buffer which holds the header.
  86.     """
  87.     chk = 256
  88.     for c in buf[:148]:
  89.         chk += ord(c)
  90.     
  91.     for c in buf[156:]:
  92.         chk += ord(c)
  93.     
  94.     return chk
  95.  
  96.  
  97. def copyfileobj(src, dst, length = None):
  98.     '''Copy length bytes from fileobj src to fileobj dst.
  99.        If length is None, copy the entire content.
  100.     '''
  101.     if length == 0:
  102.         return None
  103.     
  104.     if length is None:
  105.         shutil.copyfileobj(src, dst)
  106.         return None
  107.     
  108.     BUFSIZE = 16 * 1024
  109.     (blocks, remainder) = divmod(length, BUFSIZE)
  110.     for b in xrange(blocks):
  111.         buf = src.read(BUFSIZE)
  112.         if len(buf) < BUFSIZE:
  113.             raise IOError, 'end of file reached'
  114.         
  115.         dst.write(buf)
  116.     
  117.     if remainder != 0:
  118.         buf = src.read(remainder)
  119.         if len(buf) < remainder:
  120.             raise IOError, 'end of file reached'
  121.         
  122.         dst.write(buf)
  123.     
  124.  
  125. filemode_table = (((S_IFLNK, 'l'), (S_IFREG, '-'), (S_IFBLK, 'b'), (S_IFDIR, 'd'), (S_IFCHR, 'c'), (S_IFIFO, 'p')), ((TUREAD, 'r'),), ((TUWRITE, 'w'),), ((TUEXEC | TSUID, 's'), (TSUID, 'S'), (TUEXEC, 'x')), ((TGREAD, 'r'),), ((TGWRITE, 'w'),), ((TGEXEC | TSGID, 's'), (TSGID, 'S'), (TGEXEC, 'x')), ((TOREAD, 'r'),), ((TOWRITE, 'w'),), ((TOEXEC | TSVTX, 't'), (TSVTX, 'T'), (TOEXEC, 'x')))
  126.  
  127. def filemode(mode):
  128.     """Convert a file's mode to a string of the form
  129.        -rwxrwxrwx.
  130.        Used by TarFile.list()
  131.     """
  132.     perm = []
  133.     for table in filemode_table:
  134.         for bit, char in table:
  135.             if mode & bit == bit:
  136.                 perm.append(char)
  137.                 break
  138.                 continue
  139.         
  140.     
  141.     return ''.join(perm)
  142.  
  143. if os.sep != '/':
  144.     
  145.     normpath = lambda path: os.path.normpath(path).replace(os.sep, '/')
  146. else:
  147.     normpath = os.path.normpath
  148.  
  149. class TarError(Exception):
  150.     '''Base exception.'''
  151.     pass
  152.  
  153.  
  154. class ExtractError(TarError):
  155.     '''General exception for extract errors.'''
  156.     pass
  157.  
  158.  
  159. class ReadError(TarError):
  160.     '''Exception for unreadble tar archives.'''
  161.     pass
  162.  
  163.  
  164. class CompressionError(TarError):
  165.     '''Exception for unavailable compression methods.'''
  166.     pass
  167.  
  168.  
  169. class StreamError(TarError):
  170.     '''Exception for unsupported operations on stream-like TarFiles.'''
  171.     pass
  172.  
  173.  
  174. class _LowLevelFile:
  175.     '''Low-level file object. Supports reading and writing.
  176.        It is used instead of a regular file object for streaming
  177.        access.
  178.     '''
  179.     
  180.     def __init__(self, name, mode):
  181.         mode = {
  182.             'r': os.O_RDONLY,
  183.             'w': os.O_WRONLY | os.O_CREAT | os.O_TRUNC }[mode]
  184.         if hasattr(os, 'O_BINARY'):
  185.             mode |= os.O_BINARY
  186.         
  187.         self.fd = os.open(name, mode)
  188.  
  189.     
  190.     def close(self):
  191.         os.close(self.fd)
  192.  
  193.     
  194.     def read(self, size):
  195.         return os.read(self.fd, size)
  196.  
  197.     
  198.     def write(self, s):
  199.         os.write(self.fd, s)
  200.  
  201.  
  202.  
  203. class _Stream:
  204.     '''Class that serves as an adapter between TarFile and
  205.        a stream-like object.  The stream-like object only
  206.        needs to have a read() or write() method and is accessed
  207.        blockwise.  Use of gzip or bzip2 compression is possible.
  208.        A stream-like object could be for example: sys.stdin,
  209.        sys.stdout, a socket, a tape device etc.
  210.  
  211.        _Stream is intended to be used only internally.
  212.     '''
  213.     
  214.     def __init__(self, name, mode, type, fileobj, bufsize):
  215.         '''Construct a _Stream object.
  216.         '''
  217.         self._extfileobj = True
  218.         if fileobj is None:
  219.             fileobj = _LowLevelFile(name, mode)
  220.             self._extfileobj = False
  221.         
  222.         if not name:
  223.             pass
  224.         self.name = ''
  225.         self.mode = mode
  226.         self.type = type
  227.         self.fileobj = fileobj
  228.         self.bufsize = bufsize
  229.         self.buf = ''
  230.         self.pos = 0x0L
  231.         self.closed = False
  232.         if type == 'gz':
  233.             
  234.             try:
  235.                 import zlib
  236.             except ImportError:
  237.                 raise CompressionError, 'zlib module is not available'
  238.  
  239.             self.zlib = zlib
  240.             self.crc = zlib.crc32('')
  241.             if mode == 'r':
  242.                 self._init_read_gz()
  243.             else:
  244.                 self._init_write_gz()
  245.         
  246.         if type == 'bz2':
  247.             
  248.             try:
  249.                 import bz2
  250.             except ImportError:
  251.                 raise CompressionError, 'bz2 module is not available'
  252.  
  253.             if mode == 'r':
  254.                 self.dbuf = ''
  255.                 self.cmp = bz2.BZ2Decompressor()
  256.             else:
  257.                 self.cmp = bz2.BZ2Compressor()
  258.         
  259.  
  260.     
  261.     def __del__(self):
  262.         if not self.closed:
  263.             self.close()
  264.         
  265.  
  266.     
  267.     def _init_write_gz(self):
  268.         '''Initialize for writing with gzip compression.
  269.         '''
  270.         self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED, -(self.zlib.MAX_WBITS), self.zlib.DEF_MEM_LEVEL, 0)
  271.         timestamp = struct.pack('<L', long(time.time()))
  272.         self._Stream__write('\x1f\x8b\x08\x08%s\x02\xff' % timestamp)
  273.         if self.name.endswith('.gz'):
  274.             self.name = self.name[:-3]
  275.         
  276.         self._Stream__write(self.name + NUL)
  277.  
  278.     
  279.     def write(self, s):
  280.         '''Write string s to the stream.
  281.         '''
  282.         if self.type == 'gz':
  283.             self.crc = self.zlib.crc32(s, self.crc)
  284.         
  285.         self.pos += len(s)
  286.         if self.type != 'tar':
  287.             s = self.cmp.compress(s)
  288.         
  289.         self._Stream__write(s)
  290.  
  291.     
  292.     def _Stream__write(self, s):
  293.         '''Write string s to the stream if a whole new block
  294.            is ready to be written.
  295.         '''
  296.         self.buf += s
  297.         while len(self.buf) > self.bufsize:
  298.             self.fileobj.write(self.buf[:self.bufsize])
  299.             self.buf = self.buf[self.bufsize:]
  300.             continue
  301.             self
  302.  
  303.     
  304.     def close(self):
  305.         '''Close the _Stream object. No operation should be
  306.            done on it afterwards.
  307.         '''
  308.         if self.closed:
  309.             return None
  310.         
  311.         if self.mode == 'w' and self.type != 'tar':
  312.             self.buf += self.cmp.flush()
  313.         
  314.         if self.mode == 'w' and self.buf:
  315.             self.fileobj.write(self.buf)
  316.             self.buf = ''
  317.             if self.type == 'gz':
  318.                 self.fileobj.write(struct.pack('<l', self.crc))
  319.                 self.fileobj.write(struct.pack('<L', self.pos & 0xFFFFFFFFL))
  320.             
  321.         
  322.         if not self._extfileobj:
  323.             self.fileobj.close()
  324.         
  325.         self.closed = True
  326.  
  327.     
  328.     def _init_read_gz(self):
  329.         '''Initialize for reading a gzip compressed fileobj.
  330.         '''
  331.         self.cmp = self.zlib.decompressobj(-(self.zlib.MAX_WBITS))
  332.         self.dbuf = ''
  333.         if self._Stream__read(2) != '\x1f\x8b':
  334.             raise ReadError, 'not a gzip file'
  335.         
  336.         if self._Stream__read(1) != '\x08':
  337.             raise CompressionError, 'unsupported compression method'
  338.         
  339.         flag = ord(self._Stream__read(1))
  340.         self._Stream__read(6)
  341.         if flag & 4:
  342.             xlen = ord(self._Stream__read(1)) + 256 * ord(self._Stream__read(1))
  343.             self.read(xlen)
  344.         
  345.         if flag & 8:
  346.             while True:
  347.                 s = self._Stream__read(1)
  348.                 if not s or s == NUL:
  349.                     break
  350.                     continue
  351.         
  352.         if flag & 16:
  353.             while True:
  354.                 s = self._Stream__read(1)
  355.                 if not s or s == NUL:
  356.                     break
  357.                     continue
  358.         
  359.         if flag & 2:
  360.             self._Stream__read(2)
  361.         
  362.  
  363.     
  364.     def tell(self):
  365.         """Return the stream's file pointer position.
  366.         """
  367.         return self.pos
  368.  
  369.     
  370.     def seek(self, pos = 0):
  371.         """Set the stream's file pointer to pos. Negative seeking
  372.            is forbidden.
  373.         """
  374.         if pos - self.pos >= 0:
  375.             (blocks, remainder) = divmod(pos - self.pos, self.bufsize)
  376.             for i in xrange(blocks):
  377.                 self.read(self.bufsize)
  378.             
  379.             self.read(remainder)
  380.         else:
  381.             raise StreamError, 'seeking backwards is not allowed'
  382.         return self.pos
  383.  
  384.     
  385.     def read(self, size = None):
  386.         '''Return the next size number of bytes from the stream.
  387.            If size is not defined, return all bytes of the stream
  388.            up to EOF.
  389.         '''
  390.         if size is None:
  391.             t = []
  392.             while True:
  393.                 buf = self._read(self.bufsize)
  394.                 if not buf:
  395.                     break
  396.                 
  397.                 t.append(buf)
  398.             buf = ''.join(t)
  399.         else:
  400.             buf = self._read(size)
  401.         self.pos += len(buf)
  402.         return buf
  403.  
  404.     
  405.     def _read(self, size):
  406.         '''Return size bytes from the stream.
  407.         '''
  408.         if self.type == 'tar':
  409.             return self._Stream__read(size)
  410.         
  411.         c = len(self.dbuf)
  412.         t = [
  413.             self.dbuf]
  414.         while c < size:
  415.             buf = self._Stream__read(self.bufsize)
  416.             if not buf:
  417.                 break
  418.             
  419.             buf = self.cmp.decompress(buf)
  420.             t.append(buf)
  421.             c += len(buf)
  422.         t = ''.join(t)
  423.         self.dbuf = t[size:]
  424.         return t[:size]
  425.  
  426.     
  427.     def _Stream__read(self, size):
  428.         '''Return size bytes from stream. If internal buffer is empty,
  429.            read another block from the stream.
  430.         '''
  431.         c = len(self.buf)
  432.         t = [
  433.             self.buf]
  434.         while c < size:
  435.             buf = self.fileobj.read(self.bufsize)
  436.             if not buf:
  437.                 break
  438.             
  439.             t.append(buf)
  440.             c += len(buf)
  441.         t = ''.join(t)
  442.         self.buf = t[size:]
  443.         return t[:size]
  444.  
  445.  
  446.  
  447. class ExFileObject(object):
  448.     '''File-like object for reading an archive member.
  449.        Is returned by TarFile.extractfile(). Support for
  450.        sparse files included.
  451.     '''
  452.     
  453.     def __init__(self, tarfile, tarinfo):
  454.         self.fileobj = tarfile.fileobj
  455.         self.name = tarinfo.name
  456.         self.mode = 'r'
  457.         self.closed = False
  458.         self.offset = tarinfo.offset_data
  459.         self.size = tarinfo.size
  460.         self.pos = 0x0L
  461.         self.linebuffer = ''
  462.         if tarinfo.issparse():
  463.             self.sparse = tarinfo.sparse
  464.             self.read = self._readsparse
  465.         else:
  466.             self.read = self._readnormal
  467.  
  468.     
  469.     def __read(self, size):
  470.         '''Overloadable read method.
  471.         '''
  472.         return self.fileobj.read(size)
  473.  
  474.     
  475.     def readline(self, size = -1):
  476.         '''Read a line with approx. size. If size is negative,
  477.            read a whole line. readline() and read() must not
  478.            be mixed up (!).
  479.         '''
  480.         if size < 0:
  481.             size = sys.maxint
  482.         
  483.         nl = self.linebuffer.find('\n')
  484.         if nl >= 0:
  485.             nl = min(nl, size)
  486.         else:
  487.             size -= len(self.linebuffer)
  488.             while nl < 0 and size > 0:
  489.                 buf = self.read(min(size, 100))
  490.                 if not buf:
  491.                     break
  492.                 
  493.                 self.linebuffer += buf
  494.                 size -= len(buf)
  495.                 nl = self.linebuffer.find('\n')
  496.                 continue
  497.                 self
  498.             if nl == -1:
  499.                 s = self.linebuffer
  500.                 self.linebuffer = ''
  501.                 return s
  502.             
  503.         buf = self.linebuffer[:nl]
  504.         self.linebuffer = self.linebuffer[nl + 1:]
  505.         while buf[-1:] == '\r':
  506.             buf = buf[:-1]
  507.         return buf + '\n'
  508.  
  509.     
  510.     def readlines(self):
  511.         '''Return a list with all (following) lines.
  512.         '''
  513.         result = []
  514.         while True:
  515.             line = self.readline()
  516.             if not line:
  517.                 break
  518.             
  519.             result.append(line)
  520.         return result
  521.  
  522.     
  523.     def _readnormal(self, size = None):
  524.         '''Read operation for regular files.
  525.         '''
  526.         if self.closed:
  527.             raise ValueError, 'file is closed'
  528.         
  529.         self.fileobj.seek(self.offset + self.pos)
  530.         bytesleft = self.size - self.pos
  531.         if size is None:
  532.             bytestoread = bytesleft
  533.         else:
  534.             bytestoread = min(size, bytesleft)
  535.         self.pos += bytestoread
  536.         return self._ExFileObject__read(bytestoread)
  537.  
  538.     
  539.     def _readsparse(self, size = None):
  540.         '''Read operation for sparse files.
  541.         '''
  542.         if self.closed:
  543.             raise ValueError, 'file is closed'
  544.         
  545.         if size is None:
  546.             size = self.size - self.pos
  547.         
  548.         data = []
  549.         while size > 0:
  550.             buf = self._readsparsesection(size)
  551.             if not buf:
  552.                 break
  553.             
  554.             size -= len(buf)
  555.             data.append(buf)
  556.         return ''.join(data)
  557.  
  558.     
  559.     def _readsparsesection(self, size):
  560.         '''Read a single section of a sparse file.
  561.         '''
  562.         section = self.sparse.find(self.pos)
  563.         if section is None:
  564.             return ''
  565.         
  566.         toread = min(size, section.offset + section.size - self.pos)
  567.  
  568.     
  569.     def tell(self):
  570.         '''Return the current file position.
  571.         '''
  572.         return self.pos
  573.  
  574.     
  575.     def seek(self, pos, whence = 0):
  576.         '''Seek to a position in the file.
  577.         '''
  578.         self.linebuffer = ''
  579.         if whence == 0:
  580.             self.pos = min(max(pos, 0), self.size)
  581.         
  582.         if whence == 1:
  583.             if pos < 0:
  584.                 self.pos = max(self.pos + pos, 0)
  585.             else:
  586.                 self.pos = min(self.pos + pos, self.size)
  587.         
  588.         if whence == 2:
  589.             self.pos = max(min(self.size + pos, self.size), 0)
  590.         
  591.  
  592.     
  593.     def close(self):
  594.         '''Close the file object.
  595.         '''
  596.         self.closed = True
  597.  
  598.  
  599.  
  600. class TarInfo(object):
  601.     '''Informational class which holds the details about an
  602.        archive member given by a tar header block.
  603.        TarInfo objects are returned by TarFile.getmember(),
  604.        TarFile.getmembers() and TarFile.gettarinfo() and are
  605.        usually created internally.
  606.     '''
  607.     
  608.     def __init__(self, name = ''):
  609.         '''Construct a TarInfo object. name is the optional name
  610.            of the member.
  611.         '''
  612.         self.name = name
  613.         self.mode = 438
  614.         self.uid = 0
  615.         self.gid = 0
  616.         self.size = 0
  617.         self.mtime = 0
  618.         self.chksum = 0
  619.         self.type = REGTYPE
  620.         self.linkname = ''
  621.         self.uname = 'user'
  622.         self.gname = 'group'
  623.         self.devmajor = 0
  624.         self.devminor = 0
  625.         self.prefix = ''
  626.         self.offset = 0
  627.         self.offset_data = 0
  628.  
  629.     
  630.     def __repr__(self):
  631.         return '<%s %r at %#x>' % (self.__class__.__name__, self.name, id(self))
  632.  
  633.     
  634.     def frombuf(cls, buf):
  635.         '''Construct a TarInfo object from a 512 byte string buffer.
  636.         '''
  637.         tarinfo = cls()
  638.         tarinfo.name = nts(buf[0:100])
  639.         tarinfo.mode = int(buf[100:108], 8)
  640.         tarinfo.uid = int(buf[108:116], 8)
  641.         tarinfo.gid = int(buf[116:124], 8)
  642.         tarinfo.mtime = long(buf[136:148], 8)
  643.         tarinfo.chksum = int(buf[148:156], 8)
  644.         tarinfo.type = buf[156:157]
  645.         tarinfo.linkname = nts(buf[157:257])
  646.         tarinfo.uname = nts(buf[265:297])
  647.         tarinfo.gname = nts(buf[297:329])
  648.         
  649.         try:
  650.             tarinfo.devmajor = int(buf[329:337], 8)
  651.             tarinfo.devminor = int(buf[337:345], 8)
  652.         except ValueError:
  653.             tarinfo if buf[124] != chr(128) else tarinfo
  654.             tarinfo if buf[124] != chr(128) else tarinfo
  655.             tarinfo.devmajor = tarinfo.devmajor = 0
  656.         except:
  657.             tarinfo if buf[124] != chr(128) else tarinfo
  658.  
  659.         tarinfo.prefix = buf[345:500]
  660.         if tarinfo.isreg() and tarinfo.name.endswith('/'):
  661.             tarinfo.type = DIRTYPE
  662.         
  663.         if tarinfo.type != GNUTYPE_SPARSE:
  664.             tarinfo.name = normpath(os.path.join(nts(tarinfo.prefix), tarinfo.name))
  665.         
  666.         if tarinfo.isdir():
  667.             tarinfo.name += '/'
  668.         
  669.         return tarinfo
  670.  
  671.     frombuf = classmethod(frombuf)
  672.     
  673.     def tobuf(self):
  674.         '''Return a tar header block as a 512 byte string.
  675.         '''
  676.         if self.size <= MAXSIZE_MEMBER:
  677.             size = '%011o' % self.size
  678.         else:
  679.             s = self.size
  680.             size = ''
  681.             for i in range(11):
  682.                 size = chr(s & 255) + size
  683.                 s >>= 8
  684.             
  685.             size = chr(128) + size
  686.         parts = []
  687.         for value, fieldsize in ((self.name, 100), ('%07o' % (self.mode & 4095), 8), ('%07o' % self.uid, 8), ('%07o' % self.gid, 8), (size, 12), ('%011o' % self.mtime, 12), ('        ', 8), (self.type, 1), (self.linkname, 100), (MAGIC, 6), (VERSION, 2), (self.uname, 32), (self.gname, 32), ('%07o' % self.devmajor, 8), ('%07o' % self.devminor, 8), (self.prefix, 155)):
  688.             l = len(value)
  689.             parts.append(value[:fieldsize] + (fieldsize - l) * NUL)
  690.         
  691.         buf = ''.join(parts)
  692.         chksum = calc_chksum(buf)
  693.         buf = buf[:148] + '%06o\x00' % chksum + buf[155:]
  694.         buf += (BLOCKSIZE - len(buf)) * NUL
  695.         self.buf = buf
  696.         return buf
  697.  
  698.     
  699.     def isreg(self):
  700.         return self.type in REGULAR_TYPES
  701.  
  702.     
  703.     def isfile(self):
  704.         return self.isreg()
  705.  
  706.     
  707.     def isdir(self):
  708.         return self.type == DIRTYPE
  709.  
  710.     
  711.     def issym(self):
  712.         return self.type == SYMTYPE
  713.  
  714.     
  715.     def islnk(self):
  716.         return self.type == LNKTYPE
  717.  
  718.     
  719.     def ischr(self):
  720.         return self.type == CHRTYPE
  721.  
  722.     
  723.     def isblk(self):
  724.         return self.type == BLKTYPE
  725.  
  726.     
  727.     def isfifo(self):
  728.         return self.type == FIFOTYPE
  729.  
  730.     
  731.     def issparse(self):
  732.         return self.type == GNUTYPE_SPARSE
  733.  
  734.     
  735.     def isdev(self):
  736.         return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE)
  737.  
  738.  
  739.  
  740. class TarFile(object):
  741.     '''The TarFile Class provides an interface to tar archives.
  742.     '''
  743.     debug = 0
  744.     dereference = False
  745.     ignore_zeros = False
  746.     errorlevel = 0
  747.     posix = False
  748.     fileobject = ExFileObject
  749.     
  750.     def __init__(self, name = None, mode = 'r', fileobj = None):
  751.         """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
  752.            read from an existing archive, 'a' to append data to an existing
  753.            file or 'w' to create a new file overwriting an existing one. `mode'
  754.            defaults to 'r'.
  755.            If `fileobj' is given, it is used for reading or writing data. If it
  756.            can be determined, `mode' is overridden by `fileobj's mode.
  757.            `fileobj' is not closed, when TarFile is closed.
  758.         """
  759.         self.name = name
  760.         if len(mode) > 1 or mode not in 'raw':
  761.             raise ValueError, "mode must be 'r', 'a' or 'w'"
  762.         
  763.         self._mode = mode
  764.         self.mode = {
  765.             'r': 'rb',
  766.             'a': 'r+b',
  767.             'w': 'wb' }[mode]
  768.         if not fileobj:
  769.             fileobj = file(self.name, self.mode)
  770.             self._extfileobj = False
  771.         elif self.name is None and hasattr(fileobj, 'name'):
  772.             self.name = fileobj.name
  773.         
  774.         if hasattr(fileobj, 'mode'):
  775.             self.mode = fileobj.mode
  776.         
  777.         self._extfileobj = True
  778.         self.fileobj = fileobj
  779.         self.closed = False
  780.         self.members = []
  781.         self._loaded = False
  782.         self.offset = 0x0L
  783.         self.inodes = { }
  784.         if self._mode == 'r':
  785.             self.firstmember = None
  786.             self.firstmember = self.next()
  787.         
  788.         if self._mode == 'a':
  789.             self.firstmember = None
  790.             while True:
  791.                 
  792.                 try:
  793.                     tarinfo = self.next()
  794.                 except ReadError:
  795.                     self.fileobj.seek(0)
  796.                     break
  797.  
  798.                 if tarinfo is None:
  799.                     self.fileobj.seek(-BLOCKSIZE, 1)
  800.                     break
  801.                     continue
  802.         
  803.         if self._mode in 'aw':
  804.             self._loaded = True
  805.         
  806.  
  807.     
  808.     def open(cls, name = None, mode = 'r', fileobj = None, bufsize = 20 * 512):
  809.         """Open a tar archive for reading, writing or appending. Return
  810.            an appropriate TarFile class.
  811.  
  812.            mode:
  813.            'r'          open for reading with transparent compression
  814.            'r:'         open for reading exclusively uncompressed
  815.            'r:gz'       open for reading with gzip compression
  816.            'r:bz2'      open for reading with bzip2 compression
  817.            'a' or 'a:'  open for appending
  818.            'w' or 'w:'  open for writing without compression
  819.            'w:gz'       open for writing with gzip compression
  820.            'w:bz2'      open for writing with bzip2 compression
  821.            'r|'         open an uncompressed stream of tar blocks for reading
  822.            'r|gz'       open a gzip compressed stream of tar blocks
  823.            'r|bz2'      open a bzip2 compressed stream of tar blocks
  824.            'w|'         open an uncompressed stream for writing
  825.            'w|gz'       open a gzip compressed stream for writing
  826.            'w|bz2'      open a bzip2 compressed stream for writing
  827.         """
  828.         if not name and not fileobj:
  829.             raise ValueError, 'nothing to open'
  830.         
  831.         if ':' in mode:
  832.             (filemode, comptype) = mode.split(':', 1)
  833.             if not filemode:
  834.                 pass
  835.             filemode = 'r'
  836.             if not comptype:
  837.                 pass
  838.             comptype = 'tar'
  839.             if comptype in cls.OPEN_METH:
  840.                 func = getattr(cls, cls.OPEN_METH[comptype])
  841.             else:
  842.                 raise CompressionError, 'unknown compression type %r' % comptype
  843.             return func(name, filemode, fileobj)
  844.         elif '|' in mode:
  845.             (filemode, comptype) = mode.split('|', 1)
  846.             if not filemode:
  847.                 pass
  848.             filemode = 'r'
  849.             if not comptype:
  850.                 pass
  851.             comptype = 'tar'
  852.             if filemode not in 'rw':
  853.                 raise ValueError, "mode must be 'r' or 'w'"
  854.             
  855.             t = cls(name, filemode, _Stream(name, filemode, comptype, fileobj, bufsize))
  856.             t._extfileobj = False
  857.             return t
  858.         elif mode == 'r':
  859.             for comptype in cls.OPEN_METH:
  860.                 func = getattr(cls, cls.OPEN_METH[comptype])
  861.                 
  862.                 try:
  863.                     return func(name, 'r', fileobj)
  864.                 continue
  865.                 except (ReadError, CompressionError):
  866.                     continue
  867.                     continue
  868.                 
  869.  
  870.             
  871.             raise ReadError, 'file could not be opened successfully'
  872.         elif mode in 'aw':
  873.             return cls.taropen(name, mode, fileobj)
  874.         
  875.         raise ValueError, 'undiscernible mode'
  876.  
  877.     open = classmethod(open)
  878.     
  879.     def taropen(cls, name, mode = 'r', fileobj = None):
  880.         '''Open uncompressed tar archive name for reading or writing.
  881.         '''
  882.         if len(mode) > 1 or mode not in 'raw':
  883.             raise ValueError, "mode must be 'r', 'a' or 'w'"
  884.         
  885.         return cls(name, mode, fileobj)
  886.  
  887.     taropen = classmethod(taropen)
  888.     
  889.     def gzopen(cls, name, mode = 'r', fileobj = None, compresslevel = 9):
  890.         '''Open gzip compressed tar archive name for reading or writing.
  891.            Appending is not allowed.
  892.         '''
  893.         if len(mode) > 1 or mode not in 'rw':
  894.             raise ValueError, "mode must be 'r' or 'w'"
  895.         
  896.         
  897.         try:
  898.             import gzip
  899.             gzip.GzipFile
  900.         except (ImportError, AttributeError):
  901.             raise CompressionError, 'gzip module is not available'
  902.  
  903.         (pre, ext) = os.path.splitext(name)
  904.         pre = os.path.basename(pre)
  905.         if ext == '.tgz':
  906.             ext = '.tar'
  907.         
  908.         if ext == '.gz':
  909.             ext = ''
  910.         
  911.         tarname = pre + ext
  912.         if fileobj is None:
  913.             fileobj = file(name, mode + 'b')
  914.         
  915.         if mode != 'r':
  916.             name = tarname
  917.         
  918.         
  919.         try:
  920.             t = cls.taropen(tarname, mode, gzip.GzipFile(name, mode, compresslevel, fileobj))
  921.         except IOError:
  922.             raise ReadError, 'not a gzip file'
  923.  
  924.         t._extfileobj = False
  925.         return t
  926.  
  927.     gzopen = classmethod(gzopen)
  928.     
  929.     def bz2open(cls, name, mode = 'r', fileobj = None, compresslevel = 9):
  930.         '''Open bzip2 compressed tar archive name for reading or writing.
  931.            Appending is not allowed.
  932.         '''
  933.         if len(mode) > 1 or mode not in 'rw':
  934.             raise ValueError, "mode must be 'r' or 'w'."
  935.         
  936.         
  937.         try:
  938.             import bz2
  939.         except ImportError:
  940.             raise CompressionError, 'bz2 module is not available'
  941.  
  942.         (pre, ext) = os.path.splitext(name)
  943.         pre = os.path.basename(pre)
  944.         if ext == '.tbz2':
  945.             ext = '.tar'
  946.         
  947.         if ext == '.bz2':
  948.             ext = ''
  949.         
  950.         tarname = pre + ext
  951.         if fileobj is not None:
  952.             raise ValueError, 'no support for external file objects'
  953.         
  954.         
  955.         try:
  956.             t = cls.taropen(tarname, mode, bz2.BZ2File(name, mode, compresslevel = compresslevel))
  957.         except IOError:
  958.             raise ReadError, 'not a bzip2 file'
  959.  
  960.         t._extfileobj = False
  961.         return t
  962.  
  963.     bz2open = classmethod(bz2open)
  964.     OPEN_METH = {
  965.         'tar': 'taropen',
  966.         'gz': 'gzopen',
  967.         'bz2': 'bz2open' }
  968.     
  969.     def close(self):
  970.         '''Close the TarFile. In write-mode, two finishing zero blocks are
  971.            appended to the archive.
  972.         '''
  973.         if self.closed:
  974.             return None
  975.         
  976.         if self._mode in 'aw':
  977.             self.fileobj.write(NUL * BLOCKSIZE * 2)
  978.             self.offset += BLOCKSIZE * 2
  979.             (blocks, remainder) = divmod(self.offset, RECORDSIZE)
  980.             if remainder > 0:
  981.                 self.fileobj.write(NUL * (RECORDSIZE - remainder))
  982.             
  983.         
  984.         if not self._extfileobj:
  985.             self.fileobj.close()
  986.         
  987.         self.closed = True
  988.  
  989.     
  990.     def getmember(self, name):
  991.         """Return a TarInfo object for member `name'. If `name' can not be
  992.            found in the archive, KeyError is raised. If a member occurs more
  993.            than once in the archive, its last occurence is assumed to be the
  994.            most up-to-date version.
  995.         """
  996.         tarinfo = self._getmember(name)
  997.         if tarinfo is None:
  998.             raise KeyError, 'filename %r not found' % name
  999.         
  1000.         return tarinfo
  1001.  
  1002.     
  1003.     def getmembers(self):
  1004.         '''Return the members of the archive as a list of TarInfo objects. The
  1005.            list has the same order as the members in the archive.
  1006.         '''
  1007.         self._check()
  1008.         if not self._loaded:
  1009.             self._load()
  1010.         
  1011.         return self.members
  1012.  
  1013.     
  1014.     def getnames(self):
  1015.         '''Return the members of the archive as a list of their names. It has
  1016.            the same order as the list returned by getmembers().
  1017.         '''
  1018.         return [ tarinfo.name for tarinfo in self.getmembers() ]
  1019.  
  1020.     
  1021.     def gettarinfo(self, name = None, arcname = None, fileobj = None):
  1022.         """Create a TarInfo object for either the file `name' or the file
  1023.            object `fileobj' (using os.fstat on its file descriptor). You can
  1024.            modify some of the TarInfo's attributes before you add it using
  1025.            addfile(). If given, `arcname' specifies an alternative name for the
  1026.            file in the archive.
  1027.         """
  1028.         self._check('aw')
  1029.         if fileobj is not None:
  1030.             name = fileobj.name
  1031.         
  1032.         if arcname is None:
  1033.             arcname = name
  1034.         
  1035.         arcname = normpath(arcname)
  1036.         (drv, arcname) = os.path.splitdrive(arcname)
  1037.         while arcname[0:1] == '/':
  1038.             arcname = arcname[1:]
  1039.         tarinfo = TarInfo()
  1040.         if fileobj is None:
  1041.             if hasattr(os, 'lstat') and not (self.dereference):
  1042.                 statres = os.lstat(name)
  1043.             else:
  1044.                 statres = os.stat(name)
  1045.         else:
  1046.             statres = os.fstat(fileobj.fileno())
  1047.         linkname = ''
  1048.         stmd = statres.st_mode
  1049.         if stat.S_ISREG(stmd):
  1050.             inode = (statres.st_ino, statres.st_dev)
  1051.             if not (self.dereference) and statres.st_nlink > 1 and inode in self.inodes:
  1052.                 type = LNKTYPE
  1053.                 linkname = self.inodes[inode]
  1054.             else:
  1055.                 type = REGTYPE
  1056.                 if inode[0]:
  1057.                     self.inodes[inode] = arcname
  1058.                 
  1059.         elif stat.S_ISDIR(stmd):
  1060.             type = DIRTYPE
  1061.             if arcname[-1:] != '/':
  1062.                 arcname += '/'
  1063.             
  1064.         elif stat.S_ISFIFO(stmd):
  1065.             type = FIFOTYPE
  1066.         elif stat.S_ISLNK(stmd):
  1067.             type = SYMTYPE
  1068.             linkname = os.readlink(name)
  1069.         elif stat.S_ISCHR(stmd):
  1070.             type = CHRTYPE
  1071.         elif stat.S_ISBLK(stmd):
  1072.             type = BLKTYPE
  1073.         else:
  1074.             return None
  1075.         tarinfo.name = arcname
  1076.         tarinfo.mode = stmd
  1077.         tarinfo.uid = statres.st_uid
  1078.         tarinfo.gid = statres.st_gid
  1079.         if stat.S_ISREG(stmd):
  1080.             tarinfo.size = statres.st_size
  1081.         else:
  1082.             tarinfo.size = 0x0L
  1083.         tarinfo.mtime = statres.st_mtime
  1084.         tarinfo.type = type
  1085.         tarinfo.linkname = linkname
  1086.         if pwd:
  1087.             
  1088.             try:
  1089.                 tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0]
  1090.             except KeyError:
  1091.                 pass
  1092.             except:
  1093.                 None<EXCEPTION MATCH>KeyError
  1094.             
  1095.  
  1096.         None<EXCEPTION MATCH>KeyError
  1097.         if grp:
  1098.             
  1099.             try:
  1100.                 tarinfo.gname = grp.getgrgid(tarinfo.gid)[0]
  1101.             except KeyError:
  1102.                 pass
  1103.             except:
  1104.                 None<EXCEPTION MATCH>KeyError
  1105.             
  1106.  
  1107.         None<EXCEPTION MATCH>KeyError
  1108.         if type in (CHRTYPE, BLKTYPE):
  1109.             if hasattr(os, 'major') and hasattr(os, 'minor'):
  1110.                 tarinfo.devmajor = os.major(statres.st_rdev)
  1111.                 tarinfo.devminor = os.minor(statres.st_rdev)
  1112.             
  1113.         
  1114.         return tarinfo
  1115.  
  1116.     
  1117.     def list(self, verbose = True):
  1118.         """Print a table of contents to sys.stdout. If `verbose' is False, only
  1119.            the names of the members are printed. If it is True, an `ls -l'-like
  1120.            output is produced.
  1121.         """
  1122.         self._check()
  1123.         for tarinfo in self:
  1124.             if verbose:
  1125.                 print filemode(tarinfo.mode),
  1126.                 if not tarinfo.uname:
  1127.                     pass
  1128.                 if not tarinfo.gname:
  1129.                     pass
  1130.                 print '%s/%s' % (tarinfo.uid, tarinfo.gid),
  1131.                 if tarinfo.ischr() or tarinfo.isblk():
  1132.                     print '%10s' % '%d,%d' % (tarinfo.devmajor, tarinfo.devminor),
  1133.                 else:
  1134.                     print '%10d' % tarinfo.size,
  1135.                 print '%d-%02d-%02d %02d:%02d:%02d' % time.localtime(tarinfo.mtime)[:6],
  1136.             
  1137.             print tarinfo.name,
  1138.             if verbose:
  1139.                 if tarinfo.issym():
  1140.                     print '->', tarinfo.linkname,
  1141.                 
  1142.                 if tarinfo.islnk():
  1143.                     print 'link to', tarinfo.linkname,
  1144.                 
  1145.             
  1146.             print 
  1147.         
  1148.  
  1149.     
  1150.     def add(self, name, arcname = None, recursive = True):
  1151.         """Add the file `name' to the archive. `name' may be any type of file
  1152.            (directory, fifo, symbolic link, etc.). If given, `arcname'
  1153.            specifies an alternative name for the file in the archive.
  1154.            Directories are added recursively by default. This can be avoided by
  1155.            setting `recursive' to False.
  1156.         """
  1157.         self._check('aw')
  1158.         if arcname is None:
  1159.             arcname = name
  1160.         
  1161.         if self.name is not None and os.path.abspath(name) == os.path.abspath(self.name):
  1162.             self._dbg(2, 'tarfile: Skipped %r' % name)
  1163.             return None
  1164.         
  1165.         if name == '.':
  1166.             if recursive:
  1167.                 if arcname == '.':
  1168.                     arcname = ''
  1169.                 
  1170.                 for f in os.listdir('.'):
  1171.                     self.add(f, os.path.join(arcname, f))
  1172.                 
  1173.             
  1174.             return None
  1175.         
  1176.         self._dbg(1, name)
  1177.         tarinfo = self.gettarinfo(name, arcname)
  1178.         if tarinfo is None:
  1179.             self._dbg(1, 'tarfile: Unsupported type %r' % name)
  1180.             return None
  1181.         
  1182.         if tarinfo.isreg():
  1183.             f = file(name, 'rb')
  1184.             self.addfile(tarinfo, f)
  1185.             f.close()
  1186.         elif tarinfo.isdir():
  1187.             self.addfile(tarinfo)
  1188.             if recursive:
  1189.                 for f in os.listdir(name):
  1190.                     self.add(os.path.join(name, f), os.path.join(arcname, f))
  1191.                 
  1192.             
  1193.         else:
  1194.             self.addfile(tarinfo)
  1195.  
  1196.     
  1197.     def addfile(self, tarinfo, fileobj = None):
  1198.         """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
  1199.            given, tarinfo.size bytes are read from it and added to the archive.
  1200.            You can create TarInfo objects using gettarinfo().
  1201.            On Windows platforms, `fileobj' should always be opened with mode
  1202.            'rb' to avoid irritation about the file size.
  1203.         """
  1204.         self._check('aw')
  1205.         tarinfo.name = normpath(tarinfo.name)
  1206.         if tarinfo.isdir():
  1207.             tarinfo.name += '/'
  1208.         
  1209.         if tarinfo.linkname:
  1210.             tarinfo.linkname = normpath(tarinfo.linkname)
  1211.         
  1212.         if tarinfo.size > MAXSIZE_MEMBER:
  1213.             if self.posix:
  1214.                 raise ValueError, 'file is too large (>= 8 GB)'
  1215.             else:
  1216.                 self._dbg(2, 'tarfile: Created GNU tar largefile header')
  1217.         
  1218.         if len(tarinfo.linkname) > LENGTH_LINK:
  1219.             if self.posix:
  1220.                 raise ValueError, 'linkname is too long (>%d)' % LENGTH_LINK
  1221.             else:
  1222.                 self._create_gnulong(tarinfo.linkname, GNUTYPE_LONGLINK)
  1223.                 tarinfo.linkname = tarinfo.linkname[:LENGTH_LINK - 1]
  1224.                 self._dbg(2, 'tarfile: Created GNU tar extension LONGLINK')
  1225.         
  1226.         if len(tarinfo.name) > LENGTH_NAME:
  1227.             if self.posix:
  1228.                 prefix = tarinfo.name[:LENGTH_PREFIX + 1]
  1229.                 while prefix and prefix[-1] != '/':
  1230.                     prefix = prefix[:-1]
  1231.                 name = tarinfo.name[len(prefix):]
  1232.                 prefix = prefix[:-1]
  1233.                 if not prefix or len(name) > LENGTH_NAME:
  1234.                     raise ValueError, 'name is too long (>%d)' % LENGTH_NAME
  1235.                 
  1236.                 tarinfo.name = name
  1237.                 tarinfo.prefix = prefix
  1238.             else:
  1239.                 self._create_gnulong(tarinfo.name, GNUTYPE_LONGNAME)
  1240.                 tarinfo.name = tarinfo.name[:LENGTH_NAME - 1]
  1241.                 self._dbg(2, 'tarfile: Created GNU tar extension LONGNAME')
  1242.         
  1243.         self.fileobj.write(tarinfo.tobuf())
  1244.         self.offset += BLOCKSIZE
  1245.         if fileobj is not None:
  1246.             copyfileobj(fileobj, self.fileobj, tarinfo.size)
  1247.             (blocks, remainder) = divmod(tarinfo.size, BLOCKSIZE)
  1248.             if remainder > 0:
  1249.                 self.fileobj.write(NUL * (BLOCKSIZE - remainder))
  1250.                 blocks += 1
  1251.             
  1252.             self.offset += blocks * BLOCKSIZE
  1253.         
  1254.         self.members.append(tarinfo)
  1255.  
  1256.     
  1257.     def extract(self, member, path = ''):
  1258.         """Extract a member from the archive to the current working directory,
  1259.            using its full name. Its file information is extracted as accurately
  1260.            as possible. `member' may be a filename or a TarInfo object. You can
  1261.            specify a different directory using `path'.
  1262.         """
  1263.         self._check('r')
  1264.         if isinstance(member, TarInfo):
  1265.             tarinfo = member
  1266.         else:
  1267.             tarinfo = self.getmember(member)
  1268.         if tarinfo.islnk():
  1269.             tarinfo._link_target = os.path.join(path, tarinfo.linkname)
  1270.         
  1271.         
  1272.         try:
  1273.             self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
  1274.         except EnvironmentError:
  1275.             e = None
  1276.             if self.errorlevel > 0:
  1277.                 raise 
  1278.             elif e.filename is None:
  1279.                 self._dbg(1, 'tarfile: %s' % e.strerror)
  1280.             else:
  1281.                 self._dbg(1, 'tarfile: %s %r' % (e.strerror, e.filename))
  1282.         except ExtractError:
  1283.             e = None
  1284.             if self.errorlevel > 1:
  1285.                 raise 
  1286.             else:
  1287.                 self._dbg(1, 'tarfile: %s' % e)
  1288.         except:
  1289.             self.errorlevel > 1
  1290.  
  1291.  
  1292.     
  1293.     def extractfile(self, member):
  1294.         """Extract a member from the archive as a file object. `member' may be
  1295.            a filename or a TarInfo object. If `member' is a regular file, a
  1296.            file-like object is returned. If `member' is a link, a file-like
  1297.            object is constructed from the link's target. If `member' is none of
  1298.            the above, None is returned.
  1299.            The file-like object is read-only and provides the following
  1300.            methods: read(), readline(), readlines(), seek() and tell()
  1301.         """
  1302.         self._check('r')
  1303.         if isinstance(member, TarInfo):
  1304.             tarinfo = member
  1305.         else:
  1306.             tarinfo = self.getmember(member)
  1307.         if tarinfo.isreg():
  1308.             return self.fileobject(self, tarinfo)
  1309.         elif tarinfo.type not in SUPPORTED_TYPES:
  1310.             return self.fileobject(self, tarinfo)
  1311.         elif tarinfo.islnk() or tarinfo.issym():
  1312.             if isinstance(self.fileobj, _Stream):
  1313.                 raise StreamError, 'cannot extract (sym)link as file object'
  1314.             else:
  1315.                 return self.extractfile(self._getmember(tarinfo.linkname, tarinfo))
  1316.         else:
  1317.             return None
  1318.  
  1319.     
  1320.     def _extract_member(self, tarinfo, targetpath):
  1321.         '''Extract the TarInfo object tarinfo to a physical
  1322.            file called targetpath.
  1323.         '''
  1324.         if targetpath[-1:] == '/':
  1325.             targetpath = targetpath[:-1]
  1326.         
  1327.         targetpath = os.path.normpath(targetpath)
  1328.         upperdirs = os.path.dirname(targetpath)
  1329.         if upperdirs and not os.path.exists(upperdirs):
  1330.             ti = TarInfo()
  1331.             ti.name = upperdirs
  1332.             ti.type = DIRTYPE
  1333.             ti.mode = 511
  1334.             ti.mtime = tarinfo.mtime
  1335.             ti.uid = tarinfo.uid
  1336.             ti.gid = tarinfo.gid
  1337.             ti.uname = tarinfo.uname
  1338.             ti.gname = tarinfo.gname
  1339.             
  1340.             try:
  1341.                 self._extract_member(ti, ti.name)
  1342.  
  1343.         
  1344.         if tarinfo.islnk() or tarinfo.issym():
  1345.             self._dbg(1, '%s -> %s' % (tarinfo.name, tarinfo.linkname))
  1346.         else:
  1347.             self._dbg(1, tarinfo.name)
  1348.         if tarinfo.isreg():
  1349.             self.makefile(tarinfo, targetpath)
  1350.         elif tarinfo.isdir():
  1351.             self.makedir(tarinfo, targetpath)
  1352.         elif tarinfo.isfifo():
  1353.             self.makefifo(tarinfo, targetpath)
  1354.         elif tarinfo.ischr() or tarinfo.isblk():
  1355.             self.makedev(tarinfo, targetpath)
  1356.         elif tarinfo.islnk() or tarinfo.issym():
  1357.             self.makelink(tarinfo, targetpath)
  1358.         elif tarinfo.type not in SUPPORTED_TYPES:
  1359.             self.makeunknown(tarinfo, targetpath)
  1360.         else:
  1361.             self.makefile(tarinfo, targetpath)
  1362.         self.chown(tarinfo, targetpath)
  1363.         if not tarinfo.issym():
  1364.             self.chmod(tarinfo, targetpath)
  1365.             self.utime(tarinfo, targetpath)
  1366.         
  1367.  
  1368.     
  1369.     def makedir(self, tarinfo, targetpath):
  1370.         '''Make a directory called targetpath.
  1371.         '''
  1372.         
  1373.         try:
  1374.             os.mkdir(targetpath)
  1375.         except EnvironmentError:
  1376.             e = None
  1377.             if e.errno != errno.EEXIST:
  1378.                 raise 
  1379.             
  1380.         except:
  1381.             e.errno != errno.EEXIST
  1382.  
  1383.  
  1384.     
  1385.     def makefile(self, tarinfo, targetpath):
  1386.         '''Make a file called targetpath.
  1387.         '''
  1388.         source = self.extractfile(tarinfo)
  1389.         target = file(targetpath, 'wb')
  1390.         copyfileobj(source, target)
  1391.         source.close()
  1392.         target.close()
  1393.  
  1394.     
  1395.     def makeunknown(self, tarinfo, targetpath):
  1396.         '''Make a file from a TarInfo object with an unknown type
  1397.            at targetpath.
  1398.         '''
  1399.         self.makefile(tarinfo, targetpath)
  1400.         self._dbg(1, 'tarfile: Unknown file type %r, extracted as regular file.' % tarinfo.type)
  1401.  
  1402.     
  1403.     def makefifo(self, tarinfo, targetpath):
  1404.         '''Make a fifo called targetpath.
  1405.         '''
  1406.         if hasattr(os, 'mkfifo'):
  1407.             os.mkfifo(targetpath)
  1408.         else:
  1409.             raise ExtractError, 'fifo not supported by system'
  1410.  
  1411.     
  1412.     def makedev(self, tarinfo, targetpath):
  1413.         '''Make a character or block device called targetpath.
  1414.         '''
  1415.         if not hasattr(os, 'mknod') or not hasattr(os, 'makedev'):
  1416.             raise ExtractError, 'special devices not supported by system'
  1417.         
  1418.         mode = tarinfo.mode
  1419.         if tarinfo.isblk():
  1420.             mode |= stat.S_IFBLK
  1421.         else:
  1422.             mode |= stat.S_IFCHR
  1423.         os.mknod(targetpath, mode, os.makedev(tarinfo.devmajor, tarinfo.devminor))
  1424.  
  1425.     
  1426.     def makelink(self, tarinfo, targetpath):
  1427.         '''Make a (symbolic) link called targetpath. If it cannot be created
  1428.           (platform limitation), we try to make a copy of the referenced file
  1429.           instead of a link.
  1430.         '''
  1431.         linkpath = tarinfo.linkname
  1432.         
  1433.         try:
  1434.             if tarinfo.issym():
  1435.                 os.symlink(linkpath, targetpath)
  1436.             else:
  1437.                 os.link(tarinfo._link_target, targetpath)
  1438.         except AttributeError:
  1439.             if tarinfo.issym():
  1440.                 linkpath = os.path.join(os.path.dirname(tarinfo.name), linkpath)
  1441.                 linkpath = normpath(linkpath)
  1442.             
  1443.             
  1444.             try:
  1445.                 self._extract_member(self.getmember(linkpath), targetpath)
  1446.             except (EnvironmentError, KeyError):
  1447.                 e = None
  1448.                 linkpath = os.path.normpath(linkpath)
  1449.                 
  1450.                 try:
  1451.                     shutil.copy2(linkpath, targetpath)
  1452.                 except EnvironmentError:
  1453.                     e = None
  1454.                     raise IOError, 'link could not be created'
  1455.                 except:
  1456.                     None<EXCEPTION MATCH>EnvironmentError
  1457.                 
  1458.  
  1459.                 None<EXCEPTION MATCH>EnvironmentError
  1460.             
  1461.  
  1462.             None<EXCEPTION MATCH>(EnvironmentError, KeyError)
  1463.  
  1464.  
  1465.     
  1466.     def chown(self, tarinfo, targetpath):
  1467.         '''Set owner of targetpath according to tarinfo.
  1468.         '''
  1469.         if pwd and hasattr(os, 'geteuid') and os.geteuid() == 0:
  1470.             
  1471.             try:
  1472.                 g = grp.getgrnam(tarinfo.gname)[2]
  1473.             except KeyError:
  1474.                 
  1475.                 try:
  1476.                     g = grp.getgrgid(tarinfo.gid)[2]
  1477.                 except KeyError:
  1478.                     g = os.getgid()
  1479.                 except:
  1480.                     None<EXCEPTION MATCH>KeyError
  1481.                 
  1482.  
  1483.                 None<EXCEPTION MATCH>KeyError
  1484.  
  1485.             
  1486.             try:
  1487.                 u = pwd.getpwnam(tarinfo.uname)[2]
  1488.             except KeyError:
  1489.                 
  1490.                 try:
  1491.                     u = pwd.getpwuid(tarinfo.uid)[2]
  1492.                 except KeyError:
  1493.                     u = os.getuid()
  1494.                 except:
  1495.                     None<EXCEPTION MATCH>KeyError
  1496.                 
  1497.  
  1498.                 None<EXCEPTION MATCH>KeyError
  1499.  
  1500.             
  1501.             try:
  1502.                 if tarinfo.issym() and hasattr(os, 'lchown'):
  1503.                     os.lchown(targetpath, u, g)
  1504.                 elif sys.platform != 'os2emx':
  1505.                     os.chown(targetpath, u, g)
  1506.             except EnvironmentError:
  1507.                 e = None
  1508.                 raise ExtractError, 'could not change owner'
  1509.             except:
  1510.                 None<EXCEPTION MATCH>EnvironmentError
  1511.             
  1512.  
  1513.         None<EXCEPTION MATCH>EnvironmentError
  1514.  
  1515.     
  1516.     def chmod(self, tarinfo, targetpath):
  1517.         '''Set file permissions of targetpath according to tarinfo.
  1518.         '''
  1519.         if hasattr(os, 'chmod'):
  1520.             
  1521.             try:
  1522.                 os.chmod(targetpath, tarinfo.mode)
  1523.             except EnvironmentError:
  1524.                 e = None
  1525.                 raise ExtractError, 'could not change mode'
  1526.             except:
  1527.                 None<EXCEPTION MATCH>EnvironmentError
  1528.             
  1529.  
  1530.         None<EXCEPTION MATCH>EnvironmentError
  1531.  
  1532.     
  1533.     def utime(self, tarinfo, targetpath):
  1534.         '''Set modification time of targetpath according to tarinfo.
  1535.         '''
  1536.         if not hasattr(os, 'utime'):
  1537.             return None
  1538.         
  1539.         if sys.platform == 'win32' and tarinfo.isdir():
  1540.             return None
  1541.         
  1542.         
  1543.         try:
  1544.             os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime))
  1545.         except EnvironmentError:
  1546.             e = None
  1547.             raise ExtractError, 'could not change modification time'
  1548.  
  1549.  
  1550.     
  1551.     def next(self):
  1552.         '''Return the next member of the archive as a TarInfo object, when
  1553.            TarFile is opened for reading. Return None if there is no more
  1554.            available.
  1555.         '''
  1556.         self._check('ra')
  1557.         if self.firstmember is not None:
  1558.             m = self.firstmember
  1559.             self.firstmember = None
  1560.             return m
  1561.         
  1562.         self.fileobj.seek(self.offset)
  1563.         while True:
  1564.             buf = self.fileobj.read(BLOCKSIZE)
  1565.             if not buf:
  1566.                 return None
  1567.             
  1568.             
  1569.             try:
  1570.                 tarinfo = TarInfo.frombuf(buf)
  1571.             except ValueError:
  1572.                 if self.ignore_zeros:
  1573.                     if buf.count(NUL) == BLOCKSIZE:
  1574.                         adj = 'empty'
  1575.                     else:
  1576.                         adj = 'invalid'
  1577.                     self._dbg(2, '0x%X: %s block' % (self.offset, adj))
  1578.                     self.offset += BLOCKSIZE
  1579.                     continue
  1580.                 elif self.offset == 0:
  1581.                     raise ReadError, 'empty, unreadable or compressed file'
  1582.                 
  1583.                 return None
  1584.  
  1585.             break
  1586.         if tarinfo.chksum != calc_chksum(buf):
  1587.             self._dbg(1, 'tarfile: Bad Checksum %r' % tarinfo.name)
  1588.         
  1589.         tarinfo.offset = self.offset
  1590.         self.offset += BLOCKSIZE
  1591.         if tarinfo.type in self.TYPE_METH:
  1592.             return self.TYPE_METH[tarinfo.type](self, tarinfo)
  1593.         
  1594.         tarinfo.offset_data = self.offset
  1595.         if tarinfo.isreg() or tarinfo.type not in SUPPORTED_TYPES:
  1596.             self.offset += self._block(tarinfo.size)
  1597.         
  1598.         self.members.append(tarinfo)
  1599.         return tarinfo
  1600.  
  1601.     
  1602.     def proc_gnulong(self, tarinfo):
  1603.         '''Evaluate the blocks that hold a GNU longname
  1604.            or longlink member.
  1605.         '''
  1606.         buf = ''
  1607.         count = tarinfo.size
  1608.         while count > 0:
  1609.             block = self.fileobj.read(BLOCKSIZE)
  1610.             buf += block
  1611.             self.offset += BLOCKSIZE
  1612.             count -= BLOCKSIZE
  1613.             continue
  1614.             self
  1615.         next = self.next()
  1616.         next.offset = tarinfo.offset
  1617.         if tarinfo.type == GNUTYPE_LONGNAME:
  1618.             next.name = nts(buf)
  1619.         elif tarinfo.type == GNUTYPE_LONGLINK:
  1620.             next.linkname = nts(buf)
  1621.         
  1622.         return next
  1623.  
  1624.     
  1625.     def proc_sparse(self, tarinfo):
  1626.         '''Analyze a GNU sparse header plus extra headers.
  1627.         '''
  1628.         buf = tarinfo.tobuf()
  1629.         sp = _ringbuffer()
  1630.         pos = 386
  1631.         lastpos = 0x0L
  1632.         realpos = 0x0L
  1633.         for i in xrange(4):
  1634.             
  1635.             try:
  1636.                 offset = int(buf[pos:pos + 12], 8)
  1637.                 numbytes = int(buf[pos + 12:pos + 24], 8)
  1638.             except ValueError:
  1639.                 break
  1640.  
  1641.             if offset > lastpos:
  1642.                 sp.append(_hole(lastpos, offset - lastpos))
  1643.             
  1644.             sp.append(_data(offset, numbytes, realpos))
  1645.             realpos += numbytes
  1646.             lastpos = offset + numbytes
  1647.             pos += 24
  1648.         
  1649.         isextended = ord(buf[482])
  1650.         origsize = int(buf[483:495], 8)
  1651.         while isextended == 1:
  1652.             buf = self.fileobj.read(BLOCKSIZE)
  1653.             self.offset += BLOCKSIZE
  1654.             pos = 0
  1655.             for i in xrange(21):
  1656.                 
  1657.                 try:
  1658.                     offset = int(buf[pos:pos + 12], 8)
  1659.                     numbytes = int(buf[pos + 12:pos + 24], 8)
  1660.                 except ValueError:
  1661.                     self
  1662.                     self
  1663.                     break
  1664.                 except:
  1665.                     self
  1666.  
  1667.                 if offset > lastpos:
  1668.                     sp.append(_hole(lastpos, offset - lastpos))
  1669.                 
  1670.                 sp.append(_data(offset, numbytes, realpos))
  1671.                 realpos += numbytes
  1672.                 lastpos = offset + numbytes
  1673.                 pos += 24
  1674.             
  1675.             isextended = ord(buf[504])
  1676.         if lastpos < origsize:
  1677.             sp.append(_hole(lastpos, origsize - lastpos))
  1678.         
  1679.         tarinfo.sparse = sp
  1680.         tarinfo.offset_data = self.offset
  1681.         self.offset += self._block(tarinfo.size)
  1682.         tarinfo.size = origsize
  1683.         self.members.append(tarinfo)
  1684.         return tarinfo
  1685.  
  1686.     TYPE_METH = {
  1687.         GNUTYPE_LONGNAME: proc_gnulong,
  1688.         GNUTYPE_LONGLINK: proc_gnulong,
  1689.         GNUTYPE_SPARSE: proc_sparse }
  1690.     
  1691.     def _block(self, count):
  1692.         '''Round up a byte count by BLOCKSIZE and return it,
  1693.            e.g. _block(834) => 1024.
  1694.         '''
  1695.         (blocks, remainder) = divmod(count, BLOCKSIZE)
  1696.         if remainder:
  1697.             blocks += 1
  1698.         
  1699.         return blocks * BLOCKSIZE
  1700.  
  1701.     
  1702.     def _getmember(self, name, tarinfo = None):
  1703.         '''Find an archive member by name from bottom to top.
  1704.            If tarinfo is given, it is used as the starting point.
  1705.         '''
  1706.         members = self.getmembers()
  1707.         if tarinfo is None:
  1708.             end = len(members)
  1709.         else:
  1710.             end = members.index(tarinfo)
  1711.         for i in xrange(end - 1, -1, -1):
  1712.             if name == members[i].name:
  1713.                 return members[i]
  1714.                 continue
  1715.         
  1716.  
  1717.     
  1718.     def _load(self):
  1719.         '''Read through the entire archive file and look for readable
  1720.            members.
  1721.         '''
  1722.         while True:
  1723.             tarinfo = self.next()
  1724.             if tarinfo is None:
  1725.                 break
  1726.                 continue
  1727.         self._loaded = True
  1728.  
  1729.     
  1730.     def _check(self, mode = None):
  1731.         """Check if TarFile is still open, and if the operation's mode
  1732.            corresponds to TarFile's mode.
  1733.         """
  1734.         if self.closed:
  1735.             raise IOError, '%s is closed' % self.__class__.__name__
  1736.         
  1737.         if mode is not None and self._mode not in mode:
  1738.             raise IOError, 'bad operation for mode %r' % self._mode
  1739.         
  1740.  
  1741.     
  1742.     def __iter__(self):
  1743.         '''Provide an iterator object.
  1744.         '''
  1745.         if self._loaded:
  1746.             return iter(self.members)
  1747.         else:
  1748.             return TarIter(self)
  1749.  
  1750.     
  1751.     def _create_gnulong(self, name, type):
  1752.         '''Write a GNU longname/longlink member to the TarFile.
  1753.            It consists of an extended tar header, with the length
  1754.            of the longname as size, followed by data blocks,
  1755.            which contain the longname as a null terminated string.
  1756.         '''
  1757.         name += NUL
  1758.         tarinfo = TarInfo()
  1759.         tarinfo.name = '././@LongLink'
  1760.         tarinfo.type = type
  1761.         tarinfo.mode = 0
  1762.         tarinfo.size = len(name)
  1763.         self.fileobj.write(tarinfo.tobuf())
  1764.         self.offset += BLOCKSIZE
  1765.         self.fileobj.write(name)
  1766.         (blocks, remainder) = divmod(tarinfo.size, BLOCKSIZE)
  1767.         if remainder > 0:
  1768.             self.fileobj.write(NUL * (BLOCKSIZE - remainder))
  1769.             blocks += 1
  1770.         
  1771.         self.offset += blocks * BLOCKSIZE
  1772.  
  1773.     
  1774.     def _dbg(self, level, msg):
  1775.         '''Write debugging output to sys.stderr.
  1776.         '''
  1777.         if level <= self.debug:
  1778.             print >>sys.stderr, msg
  1779.         
  1780.  
  1781.  
  1782.  
  1783. class TarIter:
  1784.     '''Iterator Class.
  1785.  
  1786.        for tarinfo in TarFile(...):
  1787.            suite...
  1788.     '''
  1789.     
  1790.     def __init__(self, tarfile):
  1791.         '''Construct a TarIter object.
  1792.         '''
  1793.         self.tarfile = tarfile
  1794.         self.index = 0
  1795.  
  1796.     
  1797.     def __iter__(self):
  1798.         '''Return iterator object.
  1799.         '''
  1800.         return self
  1801.  
  1802.     
  1803.     def next(self):
  1804.         """Return the next item using TarFile's next() method.
  1805.            When all members have been read, set TarFile as _loaded.
  1806.         """
  1807.         if not self.tarfile._loaded:
  1808.             tarinfo = self.tarfile.next()
  1809.             if not tarinfo:
  1810.                 self.tarfile._loaded = True
  1811.                 raise StopIteration
  1812.             
  1813.         else:
  1814.             
  1815.             try:
  1816.                 tarinfo = self.tarfile.members[self.index]
  1817.             except IndexError:
  1818.                 raise StopIteration
  1819.  
  1820.         self.index += 1
  1821.         return tarinfo
  1822.  
  1823.  
  1824.  
  1825. class _section:
  1826.     '''Base class for _data and _hole.
  1827.     '''
  1828.     
  1829.     def __init__(self, offset, size):
  1830.         self.offset = offset
  1831.         self.size = size
  1832.  
  1833.     
  1834.     def __contains__(self, offset):
  1835.         return None if offset <= offset else offset < self.offset + self.size
  1836.  
  1837.  
  1838.  
  1839. class _data(_section):
  1840.     '''Represent a data section in a sparse file.
  1841.     '''
  1842.     
  1843.     def __init__(self, offset, size, realpos):
  1844.         _section.__init__(self, offset, size)
  1845.         self.realpos = realpos
  1846.  
  1847.  
  1848.  
  1849. class _hole(_section):
  1850.     '''Represent a hole section in a sparse file.
  1851.     '''
  1852.     pass
  1853.  
  1854.  
  1855. class _ringbuffer(list):
  1856.     '''Ringbuffer class which increases performance
  1857.        over a regular list.
  1858.     '''
  1859.     
  1860.     def __init__(self):
  1861.         self.idx = 0
  1862.  
  1863.     
  1864.     def find(self, offset):
  1865.         idx = self.idx
  1866.         while True:
  1867.             item = self[idx]
  1868.             if offset in item:
  1869.                 break
  1870.             
  1871.             idx += 1
  1872.             if idx == len(self):
  1873.                 idx = 0
  1874.             
  1875.             if idx == self.idx:
  1876.                 return None
  1877.                 continue
  1878.         self.idx = idx
  1879.         return item
  1880.  
  1881.  
  1882. TAR_PLAIN = 0
  1883. TAR_GZIPPED = 8
  1884.  
  1885. class TarFileCompat:
  1886.     """TarFile class compatible with standard module zipfile's
  1887.        ZipFile class.
  1888.     """
  1889.     
  1890.     def __init__(self, file, mode = 'r', compression = TAR_PLAIN):
  1891.         if compression == TAR_PLAIN:
  1892.             self.tarfile = TarFile.taropen(file, mode)
  1893.         elif compression == TAR_GZIPPED:
  1894.             self.tarfile = TarFile.gzopen(file, mode)
  1895.         else:
  1896.             raise ValueError, 'unknown compression constant'
  1897.         if mode[0:1] == 'r':
  1898.             members = self.tarfile.getmembers()
  1899.             for i in xrange(len(members)):
  1900.                 m = members[i]
  1901.                 m.filename = m.name
  1902.                 m.file_size = m.size
  1903.                 m.date_time = time.gmtime(m.mtime)[:6]
  1904.             
  1905.         
  1906.  
  1907.     
  1908.     def namelist(self):
  1909.         return map((lambda m: m.name), self.infolist())
  1910.  
  1911.     
  1912.     def infolist(self):
  1913.         return filter((lambda m: m.type in REGULAR_TYPES), self.tarfile.getmembers())
  1914.  
  1915.     
  1916.     def printdir(self):
  1917.         self.tarfile.list()
  1918.  
  1919.     
  1920.     def testzip(self):
  1921.         pass
  1922.  
  1923.     
  1924.     def getinfo(self, name):
  1925.         return self.tarfile.getmember(name)
  1926.  
  1927.     
  1928.     def read(self, name):
  1929.         return self.tarfile.extractfile(self.tarfile.getmember(name)).read()
  1930.  
  1931.     
  1932.     def write(self, filename, arcname = None, compress_type = None):
  1933.         self.tarfile.add(filename, arcname)
  1934.  
  1935.     
  1936.     def writestr(self, zinfo, bytes):
  1937.         import StringIO
  1938.         import calendar
  1939.         zinfo.name = zinfo.filename
  1940.         zinfo.size = zinfo.file_size
  1941.         zinfo.mtime = calendar.timegm(zinfo.date_time)
  1942.         self.tarfile.addfile(zinfo, StringIO.StringIO(bytes))
  1943.  
  1944.     
  1945.     def close(self):
  1946.         self.tarfile.close()
  1947.  
  1948.  
  1949.  
  1950. def is_tarfile(name):
  1951.     '''Return True if name points to a tar archive that we
  1952.        are able to handle, else return False.
  1953.     '''
  1954.     
  1955.     try:
  1956.         t = open(name)
  1957.         t.close()
  1958.         return True
  1959.     except TarError:
  1960.         return False
  1961.  
  1962.  
  1963. open = TarFile.open
  1964.